
`include "common_header.verilog"

//  *************************************************************************
//  File : mtip_pushdata_xsync
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2008 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Daniel Koehler
//  info@morethanip.com
//  *************************************************************************
//  Description : Synchronization module to transfer a vector of data
//                to another clock domain and generating a valid pulse as
//                soon as the value has reached the read side.
// 
//                The principle is a small FIFO of 2 entries, which are
//                written alternating. The read collects data alternating
//                and indicates valid when a new data has been written and
//                has reached the output.
// 
//  Requirements: It allows transfering information with a minimum distance
//                of 3 clock cycles on the write side. The read side clock
//                must be at minimum (write clock)/1.5 or higher.
// 
//       Note:   This module is required only to allow the read clock to
//               be slower than the write clock. If the read clock is
//               same as write or higher, then a simpler mechanism with a 
//               single entry would be sufficient (however this module
//               still works fine but is wasting resources especially if
//               the data vector is large).
// 
//  Version     : $Id: mtip_pushdata_xsync.v,v 1.1.1.1 2011/05/13 07:47:11 dk Exp $
//  *************************************************************************

module mtip_pushdata_xsync (
   
   reset_wclk,
   wclk,
   din_val,
   din,
   reset_rclk,
   rclk,
   dout_val,
   dout);

parameter NWIDTH = 32;          // number of bits for the data vector

input   reset_wclk;             //  Active High Reset for write domain
input   wclk;                   //  write clock
input   din_val;                //  write data valid (rising edge detect is done)
input   [NWIDTH - 1:0] din;     //  write data
input   reset_rclk;             //  Asynchronous Reset - read domain
input   rclk;                   //  read
output   dout_val;              //  read data valid (single pulse)
output   [NWIDTH - 1:0] dout;   //  read data

reg     dout_val; 
reg     [NWIDTH - 1:0] dout; 

// write clock domain
reg     l_val_d; 
reg     [NWIDTH - 1:0] l_din1; //  FIFO data word1
reg     [NWIDTH - 1:0] l_din2; //  FIFO data word2
reg     l_tog; 

//  output clock domain
wire    r_tog; 
reg     r_tog_d; 
reg     dout_load; 

//  prepare for clock domain crossing, latching the value one cycle after the valid did assert.
//  We know that the tx_ts_int values are latched within MAC, hence here we can rely on that.
// 
always @(posedge reset_wclk or posedge wclk)
   begin : process_1
   if (reset_wclk == 1'b 1)
      begin
      l_val_d   <= 1'b 0;	
      l_tog     <= 1'b 0;	
      l_din1    <= {NWIDTH{1'b 0}};	
      l_din2    <= {NWIDTH{1'b 0}};	
      end
   else
      begin
      l_val_d <= din_val;	

        //  generate toggle signal to other clock domain to control read

      if (l_val_d == 1'b 0 & din_val == 1'b 1)
         begin
         l_tog <= ~l_tog;	
         end

        //  latch write data into two separate registers to have alternating sources, 
        //  as a data may come within only 2-3 clock cycles which would not be enough
        //  to latch the result on the output if the read clock is slower.
        //  We basically emulate a 2-entries FIFO here.
        
      if (l_val_d == 1'b 0 & din_val == 1'b 1)
         begin
         if (l_tog == 1'b 0)
            begin
            l_din1 <= din;	
            end
         else
            begin
            l_din2 <= din;	
            end
         end

      end
   end

//  ------------------------                
//  transfer the toggle bit into read clock domain
//  ------------------------ 
               
mtip_xsync #(1) U_TOGSYNC (
          .data_in(l_tog),      //  from write clock domain
          .reset(reset_rclk),
          .clk(rclk),
          .data_s(r_tog));
          
//  ------------------------                
//  read clock domain
//  ------------------------                

//  forward data from the correct entry based on the toggle information.
always @(posedge reset_rclk or posedge rclk)
   begin : process_2
   if (reset_rclk == 1'b 1)
      begin
      r_tog_d   <= 1'b 0;	
      dout_load <= 1'b 0;
      dout_val  <= 1'b 0;	
      dout      <= {NWIDTH{1'b 0}};	
      end
   else
      begin
      r_tog_d <= r_tog;	

        // load the output data
      dout_load <= r_tog ^ r_tog_d;

        //  provide data valid pulse one cycle later
      dout_val <= dout_load;

        //  provide data depending on currently valid data set (like a FIFO read)
      if (dout_load == 1'b 1)
         begin
         if (r_tog_d == 1'b 1)
            begin
                   //  when tog is now 1 we have to get the data that was written when l_tog was 0.
            dout <= l_din1;	//  multicycle, max 2x rclk cycles
            end
         else
            begin
            dout <= l_din2;	//  multicycle, max 2x rclk cycles
            end
         end

      end
   end

`ifdef MTIP_XSYNC_DISPLAY
initial $display("mtip_pushdata_xsync:%m.dout[%0d:0]",NWIDTH-1);
`endif

endmodule // module mtip_pushdata_xsync

